package paylayer

import (
	"strconv"
	"errors"
	"time"
	"dhfshop/utils/uuid"
	"dhfshop/models/misc"
	"encoding/json"
	"dhfshop/models/sale"
	"dhfshop/models/consts"
	"dhfshop/models/shopping"
	"github.com/astaxie/beego"
	"dhfshop/service/nsqcli"
	"dhfshop/domain/pushmsg"
	"dhfshop/service/gcpool"
	"dhfshop/models/print"
	"dhfshop/service/event"
)


func sendPaySuccessMsg(orderId int64) {
	paySuccessNsq := struct {
		OrderIdStr string `json:"order_id"`
		CreatedAt  int64  `json:"time"`
	}{OrderIdStr:strconv.FormatInt(orderId, 10),CreatedAt:time.Now().UTC().Unix()}
	if b, err := json.Marshal(paySuccessNsq); err == nil {
		//beego.Debug("GeneralMsgAfterPayment msg:", string(b))
		address := beego.AppConfig.String("NsqUrl")
		topic := "GeneralMsgAfterPayment"
		if err = nsqcli.StartProducer(address, topic, b); err != nil {
			beego.Debug("StartProducer err:", err.Error())
		}
	}
}

func sendFxMsg(orderId int64, fxRef string) {
	fxNsq := struct {
		OrderIdStr string `json:"order_id"`
		FxRef      string `json:"fx_ref"`
		CreatedAt  int64  `json:"created_at"`
	}{OrderIdStr:strconv.FormatInt(orderId, 10),FxRef:fxRef,CreatedAt:time.Now().UTC().Unix()}
	if b, err := json.Marshal(fxNsq); err == nil {
		address := beego.AppConfig.String("NsqUrl")
		topic := beego.AppConfig.String("NsqTopic")
		if err = nsqcli.StartProducer(address, topic, b); err != nil {
			beego.Debug("StartProducer err:", err.Error())
		}
	}
}

func sendPinTuanMsg(items []*shopping.OrderItem,memberId,orderId int64) {
    hasPintuanId := false
	for _, item := range items {
	    if item.PintuanId > 0 {
		    hasPintuanId = true
			break
		}
	}
	if !hasPintuanId {
	   return
	}
	pinTuanNsq := struct {
		MemberIdStr string `json:"member_id"`
		OrderIdStr  string `json:"order_id"`
		CreatedAt   int64  `json:"created_at"`
	}{MemberIdStr:strconv.FormatInt(memberId,10),OrderIdStr:strconv.FormatInt(orderId,10),CreatedAt:time.Now().UTC().Unix()}
	if b, err := json.Marshal(pinTuanNsq); err == nil {
		address := beego.AppConfig.String("NsqUrl")
		topic := beego.AppConfig.String("NsqPtTopic")
		if err = nsqcli.StartProducer(address, topic, b); err != nil {
			beego.Debug("StartProducer err:", err.Error())
		}
	}
}
func JudgeAndReduceStock(order *shopping.ValueOrder) ([]*sale.Sku,map[int64]int32,error) {
	skuAndNumMap := make(map[int64]int32)
	skuKeys := make([]string, 0)
	for _, orderItem := range order.Items {
	    if value, ok := skuAndNumMap[orderItem.SkuId]; ok {
			skuAndNumMap[orderItem.SkuId] = value + orderItem.Quantity
	    } else {
			skuAndNumMap[orderItem.SkuId] = orderItem.Quantity
	    }  
	}
	for k, _:= range skuAndNumMap {
		skuKeys = append(skuKeys,strconv.FormatInt(k, 10))
	}
	fields := []string{"partner_id","sku_id","sku_stocks"}
	skus, _, err := sale.GetSkusBySkuIdArr(skuKeys, fields, 0, 200)
	if err != nil {
	   return nil, skuAndNumMap, err
	}
	for _, sku := range skus {
		if sku.SkuStocks < skuAndNumMap[sku.SkuId] {
		    return nil, skuAndNumMap, errors.New("Error: Stock Use Number Is Not Enough")
		}
		sku.SkuStocks = sku.SkuStocks - skuAndNumMap[sku.SkuId]
		sku.Item.StockNum = sku.Item.StockNum - skuAndNumMap[sku.SkuId]
		sku.Item.SaleNum = sku.Item.SaleNum + int(skuAndNumMap[sku.SkuId])
	}
	return skus, skuAndNumMap, nil
}

func ReturnStocks(order *shopping.ValueOrder) error {
	skuAndNumMap := make(map[int64]int32)
	skuKeys := make([]string, 0)
	for _, orderItem := range order.Items {
	    if value, ok := skuAndNumMap[orderItem.SkuId]; ok {
			skuAndNumMap[orderItem.SkuId] = value + orderItem.Quantity
	    } else {
			skuAndNumMap[orderItem.SkuId] = orderItem.Quantity
	    }  
	}
	for k, _:= range skuAndNumMap {
		skuKeys = append(skuKeys,strconv.FormatInt(k, 10))
	}
	fields := []string{"partner_id","sku_id","sku_stocks"}
	skus, _, err := sale.GetSkusBySkuIdArr(skuKeys, fields, 0, 200)
	if err != nil {
	   return err
	}
	for _, sku := range skus {
		sku.SkuStocks = sku.SkuStocks + skuAndNumMap[sku.SkuId]
		sku.Item.StockNum = sku.Item.StockNum + skuAndNumMap[sku.SkuId]
		sku.Item.SaleNum = sku.Item.SaleNum - int(skuAndNumMap[sku.SkuId])
		//
		stockChangeMsg(order.PartnerId,order.StoreId,sku.Item.ItemId,sku.SkuId,2,skuAndNumMap[sku.SkuId])
	}
	for _, sku := range skus {
	    beego.Debug("item stock_num, sale_num:", sku.Item.ItemId, sku.Item.StockNum, sku.Item.SaleNum)
		sale.UpdateSkuBySkuId(sku, "sku_stocks")
		sale.UpdateItemByItemId(sku.Item, "stock_num", "sale_num")
	}
	return nil
}

//topic: OrderPay、OrderReturns
func SendErpMsg(partnerId,storeId,orderId int64, notifyUrl, topic string) {
	orderIdStr := strconv.FormatInt(orderId, 10)
	msgId, _:= uuid.GetSnowFlakeId(uuid.Worker)
	curTimeStr :=  time.Now().UTC().Format(consts.DATETIME_FORMAT)
	pushMsgNew := pushmsg.PushMessageNew{MsgId:msgId,Topic:topic,PartnerId:partnerId,StoreId:storeId,
	              OrderId:orderIdStr,CreatedTime:curTimeStr}
	//
	persistMsg := new(misc.PushMsgQueue)
	persistMsg.PartnerId = partnerId
	persistMsg.StoreId = storeId
	if b, err := pushmsg.PackPushMessgeNew(&pushMsgNew); err == nil {
	   persistMsg.MsgBody = string(b)
	}
	persistMsg.Status = "FAIL"
	if len(notifyUrl) > 5 {
		if err := pushmsg.HttpPushMessge(notifyUrl, persistMsg.MsgBody); err == nil {
		   persistMsg.Status = "SUCCESS"
		}
	}
	misc.AddPushMsgQueue(persistMsg)
}

func SendPrintMsg(partnerId, storeId, orderId int64) {
	//打印队列
	printMsg := new(print.PrintQueue)
	printMsg.PartnerId = partnerId
	printMsg.StoreId = storeId
	printMsg.PrintContent = strconv.FormatInt(orderId, 10)
	//
	device := strconv.FormatInt(storeId, 10)
	msgId, _:= uuid.GetSnowFlakeId(uuid.Worker)
	msgIdStr := strconv.FormatInt(msgId, 10)
	msgBody := pushmsg.PushMsgBody{Topic:"OrderPay",PartnerId:printMsg.PartnerId,StoreId:printMsg.StoreId,
							  OrderId:printMsg.PrintContent,CreatedTime:printMsg.CreatedAtStr}
	msgBodys := []pushmsg.PushMsgBody{}	
	msgBodys = append(msgBodys, msgBody)
	msg := &pushmsg.PushMessage{MsgId:msgIdStr, Content:msgBodys}
	if data, err := pushmsg.PackPushMessge(msg); err == nil {
		gcpool.GO_CONN_POOL.GetStream("default").Add(device, data)
	}
	//第三方推送队列
	if apiInfo, err := misc.GetApiInfo(partnerId); err == nil {
	   SendErpMsg(partnerId,storeId,orderId,apiInfo.NotifyUrl,"OrderPay")
	}
}


func OrderPayAdditional(orderId int64)(err error) {
	var (
	    skus    []*sale.Sku 
	    order   *shopping.ValueOrder
		message string
	)
	skuStockChangeMap := make(map[int64]int32)
	order, err = shopping.GetOrderById(orderId)
	if err != nil {
		return
	}
	var result string = ""
	var req = new(event.TradeMsg)
	req.CompanyId = order.PartnerId
	req.UserId = order.MemberId
	req.OrderId = orderId
	req.MsgHeader.EventType = "E_ORDER_PAYMENT"
	message, err = event.EncodeMsg(req)
	if err != nil {
		return      
	}
	event.KernelBus.Publish("E_ORDER_PAYMENT",message,&result)
	if len(result) > 0 {
		errors.New(result)
		return
	}
	//支付成功，发送消息
	sendPaySuccessMsg(order.OrderId)
	
	//分销订单,需要下发消息
	if len(order.FxRef) > 0 {
	   sendFxMsg(order.OrderId, order.FxRef) 
	}
	//判断是否是拼团订单,以便下发消息
	sendPinTuanMsg(order.Items,order.MemberId,order.OrderId)
    //
	skus,skuStockChangeMap,err = JudgeAndReduceStock(order)
	if err != nil {
		beego.Emergency(err.Error())
	}
	for _, sku := range skus {
	    beego.Debug("item stock_num, sale_num:", sku.Item.ItemId, sku.Item.StockNum, sku.Item.SaleNum)
		sale.UpdateSkuBySkuId(sku, "sku_stocks")
		sale.UpdateItemByItemId(sku.Item, "stock_num", "sale_num")
		stockChangeMsg(order.PartnerId,order.StoreId,sku.Item.ItemId,sku.SkuId,1,skuStockChangeMap[sku.SkuId])
		//商品的所有sku的库存都是0时,商品需要下架
		if sku.Item.StockNum <= 0 {
			//sku.Item.OnShelves = 0                           //测试
			//sale.UpdateItemByItemId(sku.Item, "on_shelves")  //测试
			if msgBody, err := json.Marshal(sku.Item); err == nil {
				beego.Emergency("stock_num is zero", string(msgBody))
			}
			stockShortageMsg(order.PartnerId,order.StoreId,sku.Item.ItemId,sku.SkuId)
		}
	}
	//更新优惠券使用数量
	if order.MjsActivityId > 0 {
	    if mjsAct, err := shopping.GetMjsActivityById(order.MjsActivityId); err == nil {
	        if mjsAct.HType == "coupon" {
		       shopping.UpdateMjsRangeUsedNum(order.MemberId, order.MjsActivityId) 
		    }
	    }
	}
	return
}

//{"store_id":1,"partner_id":1,"type":"gendan","type1":"sku","item_id":1,"sku_id":1,"time":time()}
func stockShortageMsg(partnerId,storeId,itemId,skuId int64) {
	stockShortageNsq := struct {
		PartnerId int64 `json:"partner_id"`
		StoreId   int64 `json:"store_id"`
		Types     string `json:"type"`
		Types1    string `json:"type1"`
		ItemId  string `json:"item_id"`
		SkuId   string `json:"sku_id"`
		CurTime int64  `json:"time"`
	}{Types:"gendan",Types1:"sku"}
	stockShortageNsq.PartnerId = partnerId
	stockShortageNsq.StoreId = storeId
	stockShortageNsq.ItemId = strconv.FormatInt(itemId, 10)
	stockShortageNsq.SkuId = strconv.FormatInt(skuId, 10)
	stockShortageNsq.CurTime = time.Now().UTC().Unix()
	if b, err := json.Marshal(stockShortageNsq); err == nil {
		//beego.Debug("OrderCollection msg:", string(b))
		address := beego.AppConfig.String("NsqUrl")
		topic := "OrderCollection"
		if err = nsqcli.StartProducer(address, topic, b); err != nil {
			beego.Debug("StartProducer err:", err.Error())
		}
	}
}

//{"store_id":1,"partner_id":1,"item_id":1,"sku_id":1,"type":1,"quality":1,"time":time()}
func stockChangeMsg(partnerId,storeId,itemId,skuId int64,types,quality int32) {
	stockChangeNsq := struct {
		PartnerId int64  `json:"partner_id"`
		StoreId   int64  `json:"store_id"`
		ItemId    string `json:"item_id"`
		SkuId     string `json:"sku_id"`
		Type      int32  `json:"type"`
		Quality   int32  `json:"quality"`
		CurTime   int64  `json:"time"`
	}{}
	stockChangeNsq.PartnerId = partnerId
	stockChangeNsq.StoreId = storeId
	stockChangeNsq.ItemId = strconv.FormatInt(itemId, 10)
	stockChangeNsq.SkuId = strconv.FormatInt(skuId, 10)
	stockChangeNsq.Type = types
	stockChangeNsq.Quality = quality
	stockChangeNsq.CurTime = time.Now().UTC().Unix()
	if b, err := json.Marshal(stockChangeNsq); err == nil {
		//beego.Debug("StockChange msg:", string(b))
		address := beego.AppConfig.String("NsqUrl")
		topic := "StockChange"
		if err = nsqcli.StartProducer(address, topic, b); err != nil {
			beego.Debug("StartProducer err:", err.Error())
		}
	}
}

func sendChargeSuccessMsg(partnerId, storeId, memberId, orderId int64,payment float32) {
	chargeSuccessNsq := struct {
		PartnerId string `json:"partner_id"`
		StoreId   string `json:"store_id"`
		MemberId  string `json:"member_id"`
		Types     string `json:"type"`
		OrderId   string `json:"order_id"`
		Payment   float32 `json:"payment"`
		OrderTime int64  `json:"order_time"`
	}{Types:"balance"}
	chargeSuccessNsq.PartnerId = strconv.FormatInt(partnerId, 10)
	chargeSuccessNsq.StoreId = strconv.FormatInt(storeId, 10)
	chargeSuccessNsq.MemberId = strconv.FormatInt(memberId, 10)
	chargeSuccessNsq.OrderId = strconv.FormatInt(orderId, 10)
	chargeSuccessNsq.Payment = payment
	chargeSuccessNsq.OrderTime = time.Now().UTC().Unix()
	if b, err := json.Marshal(chargeSuccessNsq); err == nil {
		//beego.Debug("OrderCollection msg:", string(b))
		address := beego.AppConfig.String("NsqUrl")
		topic := "OrderCollection"
		if err = nsqcli.StartProducer(address, topic, b); err != nil {
			beego.Debug("StartProducer err:", err.Error())
		}
	}
}

